﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Threading;
using ThridLibray;

namespace NDK.AcqDevice.OPT
{
    public class OPTCamController : IDevice
    {
        public EventHandler<CamConnChangedEventArgs> CamConnChanged;
        private ThridLibray.IDevice cam;

        public string Name = string.Empty;
        private bool _isConnected = false;
        private CamSight camSight;

        private AutoResetEvent eventWait = new AutoResetEvent(false);//采集完成信号
        public event PropertyChangedEventHandler PropertyChanged;
        private string _status = string.Empty;
        private Bitmap _image = null;

        public bool isColor = false;
        protected virtual void OnCamConnChanged(CamConnChangedEventArgs e)
        {
            EventHandler<CamConnChangedEventArgs> handle = CamConnChanged;
            if (handle != null)
            {
                handle(this, e);
            }
        }
        public string Status
        {
            get
            {
                return _status;
            }
            private set
            {
                _status = value;
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(value.ToString()));
            }
        }
        public Bitmap Image(int timeout = 3000)
        {
            if (eventWait.WaitOne(timeout) == true)
            {
                if (_image != null)
                {
                    return _image;
                }
            }
            return null;
        }


        #region 3.0 Initialized
        /// <summary>
        /// 初始化
        /// </summary>
        public OPTCamController()
        {
            eventWait = new AutoResetEvent(false);
        }
        #endregion
        /// <summary>
        /// 获取相机连线状态
        /// </summary>
        /// <returns>true:连接；false：未连接</returns>
        public bool IsConnected
        {

            get
            {
                return _isConnected;
            }
        }

        private bool ConnectStatus
        {
            set
            {
                _isConnected = value;
                CamConnChangedEventArgs args = new CamConnChangedEventArgs();
                args.isConnect = _isConnected;
                OnCamConnChanged(args);
            }
        }
        /// <summary>
        /// 初始化相机
        /// </summary>
        /// <param name="sn">相机序列号,或则IP</param>
        /// <param name="mode">0表示连续模式，1是软触发，2是硬触发。</param>
        /// <returns></returns>
        public bool Connect(string sn, int mode)
        {
            try
            {
                /* 设备搜索 */
                List<IDeviceInfo> li = Enumerator.EnumerateDevices();
                if (li == null || li.Count <= 0)
                {
                    Status = "未找到可用相机";
                    return false;
                }

                cam = Enumerator.GetDeviceByKey(sn);
                if (cam == null)
                    return false;

                /* 注册链接事件 */
                cam.CameraOpened += OnCameraOpen;
                cam.ConnectionLost += OnConnectLoss;
                cam.CameraClosed += OnCameraClose;

                /* 打开设备 */
                if (!cam.Open())
                {
                    Status = ("连接相机失败");
                    return false;
                }

                /* 打开Software Trigger */
                cam.TriggerSet.Open(TriggerSourceEnum.Software);

                bool ret = SetImagePixel(isColor);
                ///* 设置图像格式 */
                //using (IEnumParameter p = cam.ParameterCollection[ParametrizeNameSet.ImagePixelFormat])
                //{
                //    p.SetValue("Mono8");
                //}

                /* 设置缓存个数为8（默认值为16） */
                cam.StreamGrabber.SetBufferCount(8);

                using (IBooleanParameter p = cam.ParameterCollection[ParametrizeNameSet.ImageReverseX])
                {
                    p.SetValue(true);
                }

                using (IBooleanParameter p = cam.ParameterCollection[ParametrizeNameSet.ImageReverseY])
                {
                    p.SetValue(true);
                }
                /* 注册码流回调事件 */
                cam.StreamGrabber.ImageGrabbed += OnImageGrabbed;

                /* 开启码流 */
                int times = 1;
            reOpen:
                if (!cam.GrabUsingGrabLoopThread())
                {
                    times++;
                    if (times <= 2)
                        goto reOpen;
                    Status = ("开启码流失败");
                    return false;
                }
            }
            catch (Exception ex)
            {
                return false;
            }
            return true;
        }
        /// <summary>
        /// 关闭相机
        /// </summary>
        /// <returns></returns>
        public bool Close()
        {
            try
            {
                if (cam != null && cam.IsOpen)
                {
                    cam.StreamGrabber.ImageGrabbed -= OnImageGrabbed;         /* 反注册回调 */
                    cam.ShutdownGrab();                                       /* 停止码流 */
                    cam.Close();                                              /* 关闭相机 */
                }
            }
            catch (Exception ex)
            {

                throw ex;
            }
            return true;
        }
        /// <summary>
        ///软触发相机拍照
        /// </summary>
        /// <returns></returns>
        public bool Snap(uint time = 500)
        {
            try
            {
                eventWait.Reset();
                cam.ExecuteSoftwareTrigger();
            }
            catch (Exception ex)
            {
                throw ex;
            }
            return true;
        }

        /// <summary>
        /// 图片采集回调
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void OnImageGrabbed(object sender, GrabbedEventArgs e)
        {
            var frame = e.GrabResult.Clone();

            _image = frame.ToBitmap(false);

            //_image = imgHandle(_image, camSight);

            eventWait.Set();
        }

        #region 设置相机参数

        public enum ImagePixel
        {
            Mono8,
            Mono10, Mono10Packed, Mono12, Mono12Packed,
            BayerGB8, BayerGB10, BayerGB10Packed, YUV422Packed, YUV422_8
        }
        public bool SetImagePixel(bool isColor)
        {
            if (!isColor)
            {
                /* 设置图像格式 */
                using (IEnumParameter p = cam.ParameterCollection[ParametrizeNameSet.ImagePixelFormat])
                {
                    var s = p.GetValue();
                    return p.SetValue(ImagePixel.Mono8.ToString());

                }

            }
            else
            {
                /* 设置图像格式 */
                using (IEnumParameter p = cam.ParameterCollection[ParametrizeNameSet.ImagePixelFormat])
                {
                    return p.SetValue(ImagePixel.BayerGB8.ToString());
                }
            }
        }
        public bool SetParaExposure(double exposureTime)
        {
            /* 设置曝光 */
            using (IFloatParameter p = cam.ParameterCollection[ParametrizeNameSet.ExposureTime])
            {
                p.SetValue(exposureTime);
                if (ReadParaExposure() != exposureTime)
                    return false;
            }
            return true;
        }

        public bool SetParaGain(double gainRaw)
        {
            /* 设置增益 */
            using (IFloatParameter p = cam.ParameterCollection[ParametrizeNameSet.GainRaw])
            {
                p.SetValue(gainRaw);
                if (ReadParaGain() != gainRaw)
                    return false;
            }
            return true;
        }

        public bool SetParaGama(double gamma)
        {
            /* 设置伽马 */
            using (IFloatParameter p = cam.ParameterCollection[ParametrizeNameSet.Gamma])
            {
                p.SetValue(gamma);
                if (ReadParaGama() != gamma)
                    return false;
            }
            return true;
        }

        public bool SetParaBrightness(int brightness)
        {
            /* 设置亮度 */
            using (IIntegraParameter p = cam.ParameterCollection[ParametrizeNameSet.Brightness])
            {
                p.SetValue(brightness);
                if (ReadParaBrightness() != brightness)
                    return false;
            }
            return true;
        }

        public bool SetParaDigitalshift(int digitalshift)
        {
            /* 设置数字位移 */
            using (IIntegraParameter p = cam.ParameterCollection[ParametrizeNameSet.Digitalshift])
            {
                p.SetValue(digitalshift);
                if (ReadParaDigitalshift() != digitalshift)
                    return false;
            }
            return true;
        }

        public bool SetParaContrast(int contrast)
        {
            /* 设置对比度 */
            using (IIntegraParameter p = cam.ParameterCollection[ParametrizeNameSet.Contrast])
            {
                p.SetValue(contrast);
                if (ReadParaContrast() != contrast)
                    return false;
            }
            return true;
        }

        public bool SetParaContrastThreshold(int contrastThreshold)
        {
            /* 设置对比度阈值 */
            using (IIntegraParameter p = cam.ParameterCollection[ParametrizeNameSet.ContrastThreshold])
            {
                p.SetValue(contrastThreshold);
                if (ReadParaContrastThreshold() != contrastThreshold)
                    return false;
            }
            return true;
        }

        public double ReadParaExposure()
        {
            /* 设置曝光 */
            using (IFloatParameter p = cam.ParameterCollection[ParametrizeNameSet.ExposureTime])
            {
                double temp = p.GetValue();
                return temp;
            }

        }

        public double ReadParaGain()
        {
            /* 设置增益 */
            using (IFloatParameter p = cam.ParameterCollection[ParametrizeNameSet.GainRaw])
            {
                double temp = p.GetValue();
                return temp;
            }
        }

        public double ReadParaGama()
        {
            /* 设置伽马 */
            using (IFloatParameter p = cam.ParameterCollection[ParametrizeNameSet.Gamma])
            {
                double temp = p.GetValue();
                return temp;
            }
        }

        public long ReadParaBrightness()
        {
            /* 设置亮度 */
            using (IIntegraParameter p = cam.ParameterCollection[ParametrizeNameSet.Brightness])
            {
                long temp = p.GetValue();
                return temp;
            }
        }

        public long ReadParaDigitalshift()
        {
            /* 设置数字位移 */
            using (IIntegraParameter p = cam.ParameterCollection[ParametrizeNameSet.Digitalshift])
            {
                long temp = p.GetValue();
                return temp;
            }
        }

        public long ReadParaContrast()
        {
            /* 设置对比度 */
            using (IIntegraParameter p = cam.ParameterCollection[ParametrizeNameSet.Contrast])
            {
                long temp = p.GetValue();
                return temp;
            }
        }

        public long ReadParaContrastThreshold()
        {
            /* 设置对比度阈值 */
            using (IIntegraParameter p = cam.ParameterCollection[ParametrizeNameSet.ContrastThreshold])
            {
                long temp = p.GetValue();
                return temp;
            }
        }


        public bool SetParaGain_R(double GainR)
        {
            if (GainR < 0)
                return true;
            using (IEnumParameter p = cam.ParameterCollection[new EnumName("BalanceRatioSelector")])
            {
                p.SetValue("Red");
            }
            using (IFloatParameter p = cam.ParameterCollection[new FloatName("BalanceRatio")])
            {
                p.SetValue(GainR);
                if (RedParaGain_R() - GainR > 0.5)
                    return false;
            }
            return true;
        }

        public bool SetParaGain_G(double GainG)
        {
            if (GainG < 0)
                return true;
            using (IEnumParameter p = cam.ParameterCollection[new EnumName("BalanceRatioSelector")])
            {
                p.SetValue("Green");
            }
            using (IFloatParameter p = cam.ParameterCollection[new FloatName("BalanceRatio")])
            {
                p.SetValue(GainG);
                if (RedParaGain_G() - GainG > 0.5)
                    return false;
            }
            return true;
        }

        public bool SetParaGain_B(double GainB)
        {
            if (GainB < 0)
                return true;
            using (IEnumParameter p = cam.ParameterCollection[new EnumName("BalanceRatioSelector")])
            {
                p.SetValue("Blue");
            }
            using (IFloatParameter p = cam.ParameterCollection[new FloatName("BalanceRatio")])
            {
                p.SetValue(GainB);
                if (RedParaGain_B() - GainB > 0.5)
                    return false;
            }
            return true;
        }

        public double RedParaGain_R()
        {
            using (IEnumParameter p = cam.ParameterCollection[new EnumName("BalanceRatioSelector")])
            {
                p.SetValue("Red");
            }
            using (IFloatParameter p = cam.ParameterCollection[new FloatName("BalanceRatio")])
            {
                double temp = p.GetValue();
                return temp;
            }
        }

        public double RedParaGain_G()
        {
            using (IEnumParameter p = cam.ParameterCollection[new EnumName("BalanceRatioSelector")])
            {
                p.SetValue("Green");
            }
            using (IFloatParameter p = cam.ParameterCollection[new FloatName("BalanceRatio")])
            {
                double temp = p.GetValue();
                return temp;
            }
        }

        public double RedParaGain_B()
        {
            using (IEnumParameter p = cam.ParameterCollection[new EnumName("BalanceRatioSelector")])
            {
                p.SetValue("Blue");
            }
            using (IFloatParameter p = cam.ParameterCollection[new FloatName("BalanceRatio")])
            {
                double temp = p.GetValue();
                return temp;
            }
        }
        #endregion

        /// <summary>
        /// 设置相机ROI，只能在相机grab启动前设置
        /// </summary>
        /// <param name="width"></param>
        /// <param name="height"></param>
        /// <param name="offsetX"></param>
        /// <param name="offsetY"></param>
        public void SetParaOffset(int width, int height, int offsetX, int offsetY)
        {
            using (IIntegraParameter p = cam.ParameterCollection[ParametrizeNameSet.ImageWidth])
            {
                var log = p.GetValue();
                var max = p.GetMaximum();
                var min = p.GetMinimum();
                p.SetValue(width);
            }
            using (IIntegraParameter p = cam.ParameterCollection[ParametrizeNameSet.ImageHeight])
            {
                p.SetValue(height);
            }
            using (IIntegraParameter p = cam.ParameterCollection[ParametrizeNameSet.ImageOffsetX])
            {
                p.SetValue(offsetX);
            }
            using (IIntegraParameter p = cam.ParameterCollection[ParametrizeNameSet.ImageOffsetY])
            {
                p.SetValue(offsetY);
            }
        }

        public void SetCut(CamSight cs)
        {
            camSight = cs;
        }

        private static Bitmap imgHandle(Bitmap bit, CamSight camSight)
        {
            if (camSight == null)
                return bit;
            bit = RotateFlip(bit, camSight);
            //bit = crop(bit, camSight);

            return bit;
        }
        private static Bitmap RotateFlip(Bitmap bit, CamSight camSight)
        {
            camSight.Angle = 180;
            var ro = RotateFlipType.RotateNoneFlipNone;
            if (camSight.Angle == 90) ro = RotateFlipType.Rotate90FlipNone;
            else if (camSight.Angle == 180) ro = RotateFlipType.Rotate180FlipNone;
            else if (camSight.Angle == 270) ro = RotateFlipType.Rotate270FlipNone;

            //bit.RotateFlip(ro);

            return bit;
        }
        private static Bitmap crop(Bitmap bit, CamSight cs)
        {
            if (cs.CutX < 0) cs.CutX = 0;
            if (cs.CutY < 0) cs.CutY = 0;
            if (cs.CutW > bit.Width - cs.CutX) cs.CutW = bit.Width - cs.CutX;
            if (cs.CutH > bit.Height - cs.CutY) cs.CutH = bit.Height - cs.CutY;

            if (cs.CutX > bit.Width || cs.CutY > bit.Height) return bit;
            if (cs.CutW == 0 || cs.CutH == 0) return bit;

            Rectangle cropRect = new Rectangle(cs.CutX, cs.CutY, cs.CutW, cs.CutH);
            Bitmap target = new Bitmap(cropRect.Width, cropRect.Height);
            using (Graphics g = Graphics.FromImage(target))
            {
                g.DrawImage(bit, new Rectangle(0, 0, target.Width, target.Height), cropRect, GraphicsUnit.Pixel);
            }
            return target;
        }

        #region 事件
        private void OnCameraClose(object sender, EventArgs e)
        {
            ConnectStatus = false;
            Status = $"相机已关闭:{cam.DeviceInfo}！";
        }

        private void OnConnectLoss(object sender, EventArgs e)
        {
            ConnectStatus = false;
            Status = $"相机连接断开:{cam.DeviceInfo}！";
        }

        private void OnCameraOpen(object sender, EventArgs e)
        {
            ConnectStatus = true;
            Status = $"相机已开启:{cam.DeviceInfo}！";
        }
        #endregion

    }



}
